 /*   
 * Project: OSMP
 * FileName: Modbus.java
 * version: V1.0
 */
package tk.mybatis.springboot.collector;
import java.util.Calendar;
import java.util.Date;
/**
 * Description:
 * @author: wangkaiping
 * @date: 2018年3月6日 下午4:11:13上午10:51:30
 */
public class Modbus {
	private boolean IsValid;
	  private int Code;
	  private int Address;
	  private short[] Values;
	  private Date Time;

	  public Modbus(byte[] byts)
	    throws IllegalAccessException
	  {
	    if (byts == null)
	      throw new NullPointerException();
	    if (byts.length < 5) {
	      throw new IllegalAccessException("非modbus数据帧");
	    }
	    CRC crc = CRC16(byts, byts.length - 2);
	    this.IsValid = ((crc.High == byts[(byts.length - 2)]) && (crc.low == byts[(byts.length - 1)]));
	    if (this.IsValid) {
	      this.Address = byts[0];
	      this.Code = byts[1];
	      this.Values = new short[byts[2] / 2];
	      for (int i = 3; i < this.Values.length; i++) {
	        this.Values[i] = ((short)(byts[(i * 2 + 3)] << 8 | byts[(i * 2 + 4)] & 0xFF));
	      }
	      Calendar c = Calendar.getInstance();
	      int y = byts[3] == -1 ? 1 : 2000 + (byts[3] & 0xFF);
	      int M = byts[4] == -1 ? 0 : byts[4] & 0xFF;
	      int d = byts[5] == -1 ? 1 : byts[5] & 0xFF;
	      int H = byts[6] == -1 ? 0 : byts[6] & 0xFF;
	      int m = byts[7] == -1 ? 0 : byts[7] & 0xFF;
	      int s = byts[8] == -1 ? 0 : byts[8] & 0xFF;
	      c.set(y, M-1, d, H, m, s);
	      this.Time = c.getTime();
	    }
	  }

	  /**
	   * 读取实时数据指令
	   * @param address 设备地址
	   * @param index 起始寄存器
	   * @param size 寄存器数量
	   * @return
	   */
	  public static byte[] get04Cmd(int address, int index, int size)
	  {
	    byte[] cmd = { (byte)address, 4, 0, (byte)index, 0, (byte)size, -1, -1 };
	    CRC crc = CRC16(cmd, cmd.length - 2);
	    cmd[(cmd.length - 2)] = crc.High;
	    cmd[(cmd.length - 1)] = crc.low;
	    return cmd;
	  }

	  /**
	   * 读取历史数据指令
	   * @param address 设备地址
	   * @param offset 历史数据偏移（0代表最近一条历史数据，1代表上一条，2代表上上条）
	   * @return
	   */
	  public static byte[] get41Cmd(int address, int offset) {
	    byte HH = (byte)(offset >> 24 & 0xFF);
	    byte HL = (byte)(offset >> 16 & 0xFF);
	    byte H = (byte)(offset >> 8 & 0xFF);
	    byte L = (byte)(offset & 0xFF);
	    byte[] cmd = { (byte)address, 65, HH, HL, H, L, -1, -1 };
	    CRC crc = CRC16(cmd, cmd.length - 2);
	    cmd[(cmd.length - 2)] = crc.High;
	    cmd[(cmd.length - 1)] = crc.low;
	    return cmd;
	  }

	  public int Address() {
	    return this.Address;
	  }

	  public int Code() {
	    return this.Code;
	  }

	  public boolean IsValid()
	  {
	    return this.IsValid;
	  }

	  public short getValue(int index) {
	    return this.Values[index];
	  }

	  public Date getTime() {
	    return this.Time;
	  }

	  private static CRC CRC16(byte[] byts, int len)
	  {
	    CRC crc = new CRC();

	    int CRC = 65535;
	    for (int i = 0; i < len; i++) {
	      CRC ^= byts[i] & 0xFF;
	      for (int Temp = 0; Temp < 8; Temp++) {
	        if ((CRC & 0x1) == 1)
	          CRC = CRC >> 1 ^ 0xA001;
	        else
	          CRC >>= 1;
	      }
	    }
	    crc.High = ((byte)(CRC & 0xFF));
	    crc.low = ((byte)((CRC & 0xFF00) >> 8));
	    return crc;
	  }
}
